home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / sound / cem3394.c < prev    next >
C/C++ Source or Header  |  2000-04-23  |  17KB  |  571 lines

  1. /***************************************************************************
  2.  
  3.     CEM3394 sound driver.
  4.  
  5.     This driver handles CEM-3394 analog synth chip. Very crudely.
  6.  
  7.     Still to do:
  8.         - adjust the overall volume when multiple waves are being generated
  9.         - filter internal sound
  10.         - support resonance (don't understand how it works)
  11.  
  12. ***************************************************************************/
  13.  
  14. #include "driver.h"
  15. #include <math.h>
  16.  
  17.  
  18.  
  19. /* waveform generation parameters */
  20. #define ENABLE_PULSE        1
  21. #define ENABLE_TRIANGLE        1
  22. #define ENABLE_SAWTOOTH        1
  23. #define ENABLE_EXTERNAL        1
  24.  
  25.  
  26. /* pulse shaping parameters */
  27. /* examples: */
  28. /*    hat trick - skidding ice sounds too loud if minimum width is too big */
  29. /*    snake pit - melody during first level too soft if minimum width is too small */
  30. /*    snake pit - bonus counter at the end of level */
  31. /*    snacks'n jaxson - laugh at end of level is too soft if minimum width is too small */
  32. #define LIMIT_WIDTH            1
  33. #define MINIMUM_WIDTH        0.25
  34. #define MAXIMUM_WIDTH        0.75
  35.  
  36. #define LIMIT_STEP            1
  37.  
  38.  
  39. /********************************************************************************
  40.  
  41.     From the datasheet:
  42.  
  43.     CEM3394_VCO_FREQUENCY:
  44.         -4.0 ... +4.0
  45.         -0.75 V/octave
  46.         f = exp(V) * 431.894
  47.  
  48.     CEM3394_MODULATION_AMOUNT
  49.          0.0 ... +3.5
  50.          0.0 == 0.01 x frequency
  51.          3.5 == 2.00 x frequency
  52.  
  53.     CEM3394_WAVE_SELECT
  54.         -0.5 ... -0.2 == triangle
  55.         +0.9 ... +1.5 == triangle + sawtooth
  56.         +2.3 ... +3.9 == sawtooth
  57.  
  58.     CEM3394_PULSE_WIDTH
  59.          0.0 ... +2.0
  60.          0.0 ==   0% duty cycle
  61.         +2.0 == 100% duty cycle
  62.  
  63.     CEM3394_MIXER_BALANCE
  64.         -4.0 ... +4.0
  65.          0.0 both at -6dB
  66.          -20 dB/V
  67.  
  68.     CEM3394_FILTER_RESONANCE
  69.          0.0 ... +2.5
  70.          0.0 == no resonance
  71.         +2.5 == oscillation
  72.  
  73.     CEM3394_FILTER_FREQENCY
  74.         -3.0 ... +4.0
  75.         -0.375 V/octave
  76.          0.0 == 1300Hz
  77.  
  78.     CEM3394_FINAL_GAIN
  79.          0.0 ... +4.0
  80.          -20 dB/V
  81.          0.0 == -90dB
  82.          4.0 == 0dB
  83.  
  84.     Square wave output = 160 (average is constant regardless of duty cycle)
  85.     Sawtooth output = 200
  86.     Triangle output = 250
  87.     Sawtooth + triangle output = 330
  88.     Maximum output = 400
  89.  
  90. ********************************************************************************/
  91.  
  92.  
  93. /* various waveforms */
  94. #define WAVE_TRIANGLE        1
  95. #define WAVE_SAWTOOTH        2
  96. #define WAVE_PULSE            4
  97.  
  98. /* keep lots of fractional bits */
  99. #define FRACTION_BITS        28
  100. #define FRACTION_ONE        (1 << FRACTION_BITS)
  101. #define FRACTION_ONE_D        ((double)(1 << FRACTION_BITS))
  102. #define FRACTION_MASK        (FRACTION_ONE - 1)
  103. #define FRACTION_MULT(a,b)    (((a) >> (FRACTION_BITS / 2)) * ((b) >> (FRACTION_BITS - FRACTION_BITS / 2)))
  104.  
  105.  
  106. /* this structure defines the parameters for a channel */
  107. typedef struct
  108. {
  109.     unsigned char stream;            /* our stream */
  110.     void (*external)(int, int, short *);/* callback to generate external samples */
  111.     double vco_zero_freq;            /* frequency of VCO at 0.0V */
  112.     double filter_zero_freq;        /* frequency of filter at 0.0V */
  113.  
  114.     double values[8];                /* raw values of registers */
  115.     UINT8 wave_select;                /* flags which waveforms are enabled */
  116.  
  117.     UINT32 volume;                    /* linear overall volume (0-256) */
  118.     UINT32 mixer_internal;            /* linear internal volume (0-256) */
  119.     UINT32 mixer_external;            /* linear external volume (0-256) */
  120.  
  121.     UINT32 position;                /* current VCO frequency position (0.FRACTION_BITS) */
  122.     UINT32 step;                    /* per-sample VCO step (0.FRACTION_BITS) */
  123.  
  124.     UINT32 filter_position;            /* current filter frequency position (0.FRACTION_BITS) */
  125.     UINT32 filter_step;                /* per-sample filter step (0.FRACTION_BITS) */
  126.     UINT32 modulation_depth;        /* fraction of total by which we modulate (0.FRACTION_BITS) */
  127.     INT16 last_ext;                    /* last external sample we read */
  128.  
  129.     UINT32 pulse_width;                /* fractional pulse width (0.FRACTION_BITS) */
  130. } sound_chip;
  131.  
  132.  
  133. /* data about the sound system */
  134. static sound_chip chip_list[MAX_CEM3394];
  135.  
  136. /* global sound parameters */
  137. static double inv_sample_rate;
  138. static int sample_rate;
  139.  
  140. static INT16 *mixer_buffer;
  141. static INT16 *external_buffer;
  142.  
  143.  
  144. /* generate sound to the mix buffer in mono */
  145. static void cem3394_update(int ch, INT16 *buffer, int length)
  146. {
  147.     sound_chip *chip = &chip_list[ch];
  148.     int int_volume = (chip->volume * chip->mixer_internal) / 256;
  149.     int ext_volume = (chip->volume * chip->mixer_external) / 256;
  150.     UINT32 step = chip->step, position, end_position = 0;
  151.     INT16 *mix, *ext;
  152.     int i;
  153.  
  154.     /* external volume is effectively 0 if no external function */
  155.     if (!chip->external || !ENABLE_EXTERNAL)
  156.         ext_volume = 0;
  157.  
  158.     /* adjust the volume for the filter */
  159.     if (step > chip->filter_step)
  160.         int_volume /= step - chip->filter_step;
  161.  
  162.     /* bail if nothing's going on */
  163.     if (int_volume == 0 && ext_volume == 0)
  164.     {
  165.         memset(buffer, 0, sizeof(INT16) * length);
  166.         return;
  167.     }
  168.  
  169.     /* if there's external stuff, fetch and process it now */
  170.     if (ext_volume != 0)
  171.     {
  172.         UINT32 fposition = chip->filter_position, fstep = chip->filter_step, depth;
  173.         INT16 last_ext = chip->last_ext;
  174.  
  175.         /* fetch the external data */
  176.         (*chip->external)(ch, length, external_buffer);
  177.  
  178.         /* compute the modulation depth, and adjust fstep to the maximum frequency */
  179.         /* we lop off 13 bits of depth so that we can multiply by stepadjust, below, */
  180.         /* which has 13 bits of precision */
  181.         depth = FRACTION_MULT(fstep, chip->modulation_depth);
  182.         fstep += depth;
  183.         depth >>= 13;
  184.  
  185.         /* "apply" the filter: note this is pretty cheesy; it basically just downsamples the
  186.            external sample to filter_freq by allowing only 2 transitions for every cycle */
  187.         for (i = 0, ext = external_buffer, position = chip->position; i < length; i++, ext++)
  188.         {
  189.             UINT32 newposition;
  190.             INT32 stepadjust;
  191.  
  192.             /* update the position and compute the adjustment from a triangle wave */
  193.             if (position & (1 << (FRACTION_BITS - 1)))
  194.                 stepadjust = 0x2000 - ((position >> (FRACTION_BITS - 14)) & 0x1fff);
  195.             else
  196.                 stepadjust = (position >> (FRACTION_BITS - 14)) & 0x1fff;
  197.             position += step;
  198.  
  199.             /* if we cross a half-step boundary, allow the next byte of the external input */
  200.             newposition = fposition + fstep - (stepadjust * depth);
  201.             if ((newposition ^ fposition) & ~(FRACTION_MASK >> 1))
  202.                 last_ext = *ext;
  203.             else
  204.                 *ext = last_ext;
  205.             fposition = newposition & FRACTION_MASK;
  206.         }
  207.  
  208.         /* update the final filter values */
  209.         chip->filter_position = fposition;
  210.         chip->last_ext = last_ext;
  211.     }
  212.  
  213.     /* if there's internal stuff, generate it */
  214.     if (int_volume != 0)
  215.     {
  216.         if (chip->wave_select == 0 && !ext_volume)
  217.             logerror("%f V didn't cut it\n", chip->values[CEM3394_WAVE_SELECT]);
  218.  
  219.         /* handle the pulse component; it maxes out at 0x1932, which is 27% smaller than */
  220.         /* the sawtooth (since the value is constant, this is the best place to have an */
  221.         /* odd value for volume) */
  222.         if (ENABLE_PULSE && (chip->wave_select & WAVE_PULSE))
  223.         {
  224.             UINT32 pulse_width = chip->pulse_width;
  225.  
  226.             /* this is a kludge; Snake Pit uses very small pulse widths in the tune during */
  227.             /* level 1; this makes the melody almost silent unless we enforce a minimum */
  228.             /* pulse width; even then, it's pretty tinny */
  229.             if (LIMIT_STEP)
  230.             {
  231.                 if (pulse_width <= step) pulse_width = step + 1;
  232.                 else if (pulse_width >= FRACTION_ONE - step) pulse_width = FRACTION_ONE - step - 1;
  233.             }
  234.  
  235.             /* if the width is wider than the step, we're guaranteed to hit it once per cycle */
  236.             if (pulse_width >= step)
  237.             {
  238.                 for (i = 0, mix = mixer_buffer, position = chip->position; i < length; i++, mix++)
  239.                 {
  240.                     if (position < pulse_width)
  241.                         *mix = 0x1932;
  242.                     else
  243.                         *mix = 0x0000;
  244.                     position = (position + step) & FRACTION_MASK;
  245.                 }
  246.             }
  247.  
  248.             /* otherwise, we compute a volume and watch for cycle boundary crossings */
  249.             else
  250.             {
  251.                 INT16 volume = 0x1932 * pulse_width / step;
  252.                 for (i = 0, mix = mixer_buffer, position = chip->position; i < length; i++, mix++)
  253.                 {
  254.                     UINT32 newposition = position + step;
  255.                     if ((newposition ^ position) & ~FRACTION_MASK)
  256.                         *mix = volume;
  257.                     else
  258.                         *mix = 0x0000;
  259.                     position = newposition & FRACTION_MASK;
  260.                 }
  261.             }
  262.             end_position = position;
  263.         }
  264.  
  265.         /* otherwise, clear the mixing buffer */
  266.         else
  267.             memset(mixer_buffer, 0, sizeof(INT16) * length);
  268.  
  269.         /* handle the sawtooth component; it maxes out at 0x2000, which is 27% larger */
  270.         /* than the pulse */
  271.         if (ENABLE_SAWTOOTH && (chip->wave_select & WAVE_SAWTOOTH))
  272.         {
  273.             for (i = 0, mix = mixer_buffer, position = chip->position; i < length; i++, mix++)
  274.             {
  275.                 *mix += ((position >> (FRACTION_BITS - 14)) & 0x3fff) - 0x2000;
  276.                 position += step;
  277.             }
  278.             end_position = position & FRACTION_MASK;
  279.         }
  280.  
  281.         /* handle the triangle component; it maxes out at 0x2800, which is 25% larger */
  282.         /* than the sawtooth (should be 27% according to the specs, but 25% saves us */
  283.         /* a multiplication) */
  284.         if (ENABLE_TRIANGLE && (chip->wave_select & WAVE_TRIANGLE))
  285.         {
  286.             for (i = 0, mix = mixer_buffer, position = chip->position; i < length; i++, mix++)
  287.             {
  288.                 INT16 value;
  289.                 if (position & (1 << (FRACTION_BITS - 1)))
  290.                     value = 0x2000 - ((position >> (FRACTION_BITS - 14)) & 0x1fff);
  291.                 else
  292.                     value = (position >> (FRACTION_BITS - 14)) & 0x1fff;
  293.                 *mix += value + (value >> 2);
  294.                 position += step;
  295.             }
  296.             end_position = position & FRACTION_MASK;
  297.         }
  298.  
  299.         /* update the final position */
  300.         chip->position = end_position;
  301.     }
  302.  
  303.     /* mix it down */
  304.     mix = mixer_buffer;
  305.     ext = external_buffer;
  306.     {
  307.         /* internal + external */
  308.         if (ext_volume != 0 && int_volume != 0)
  309.         {
  310.             for (i = 0; i < length; i++, mix++, ext++)
  311.                 *buffer++ = (*mix * int_volume + *ext * ext_volume) / 128;
  312.         }
  313.         /* internal only */
  314.         else if (int_volume != 0)
  315.         {
  316.             for (i = 0; i < length; i++, mix++)
  317.                 *buffer++ = *mix * int_volume / 128;
  318.         }
  319.         /* external only */
  320.         else
  321.         {
  322.             for (i = 0; i < length; i++, ext++)
  323.                 *buffer++ = *ext * ext_volume / 128;
  324.         }
  325.     }
  326. }
  327.  
  328.  
  329. int cem3394_sh_start(const struct MachineSound *msound)
  330. {
  331.     const struct cem3394_interface *intf = msound->sound_interface;
  332.     int i;
  333.  
  334.     /* bag on a 0 sample_rate */
  335.     if (Machine->sample_rate == 0)
  336.         return 0;
  337.  
  338.     /* copy global parameters */
  339.     sample_rate = Machine->sample_rate;
  340.     inv_sample_rate = 1.0 / (double)sample_rate;
  341.  
  342.     /* allocate stream channels, 1 per chip */
  343.     for (i = 0; i < intf->numchips; i++)
  344.     {
  345.         char name_buffer[100];
  346.  
  347.         memset(&chip_list[i], 0, sizeof(chip_list[i]));
  348.         sprintf(name_buffer, "CEM3394 #%d", i);
  349.         chip_list[i].stream = stream_init(name_buffer, intf->volume[i], sample_rate, i, cem3394_update);
  350.         chip_list[i].external = intf->external[i];
  351.         chip_list[i].vco_zero_freq = intf->vco_zero_freq[i];
  352.         chip_list[i].filter_zero_freq = intf->filter_zero_freq[i];
  353.     }
  354.  
  355.     /* allocate memory for a mixer buffer and external buffer (1 second should do it!) */
  356.     mixer_buffer = malloc(2 * sample_rate * sizeof(INT16));
  357.     if (!mixer_buffer)
  358.         return 1;
  359.     external_buffer = mixer_buffer + sample_rate;
  360.  
  361.     return 0;
  362. }
  363.  
  364.  
  365. void cem3394_sh_stop(void)
  366. {
  367.     if (mixer_buffer)
  368.         free(mixer_buffer);
  369.     mixer_buffer = external_buffer = NULL;
  370. }
  371.  
  372.  
  373. INLINE double compute_db(double voltage)
  374. {
  375.     /* assumes 0.0 == full off, 4.0 == full on, with linear taper, as described in the datasheet */
  376.  
  377.     /* above 4.0, maximum volume */
  378.     if (voltage >= 4.0)
  379.         return 0.0;
  380.  
  381.     /* below 0.0, minimum volume */
  382.     else if (voltage <= 0.0)
  383.         return 90.0;
  384.  
  385.     /* between 2.5 and 4.0, linear from 20dB to 0dB */
  386.     else if (voltage >= 2.5)
  387.         return (4.0 - voltage) * (1.0 / 1.5) * 20.0;
  388.  
  389.     /* between 0.0 and 2.5, exponential to 20dB */
  390.     else
  391.     {
  392.         double temp = 20.0 * pow(2.0, 2.5 - voltage);
  393.         if (temp < 90.0) return 90.0;
  394.         else return temp;
  395.     }
  396. }
  397.  
  398.  
  399. INLINE UINT32 compute_db_volume(double voltage)
  400. {
  401.     double temp;
  402.  
  403.     /* assumes 0.0 == full off, 4.0 == full on, with linear taper, as described in the datasheet */
  404.  
  405.     /* above 4.0, maximum volume */
  406.     if (voltage >= 4.0)
  407.         return 256;
  408.  
  409.     /* below 0.0, minimum volume */
  410.     else if (voltage <= 0.0)
  411.         return 0;
  412.  
  413.     /* between 2.5 and 4.0, linear from 20dB to 0dB */
  414.     else if (voltage >= 2.5)
  415.         temp = (4.0 - voltage) * (1.0 / 1.5) * 20.0;
  416.  
  417.     /* between 0.0 and 2.5, exponential to 20dB */
  418.     else
  419.     {
  420.         temp = 20.0 * pow(2.0, 2.5 - voltage);
  421.         if (temp < 50.0) return 0;
  422.     }
  423.  
  424.     /* convert from dB to volume and return */
  425.     return (UINT32)(256.0 * pow(0.891251, temp));
  426. }
  427.  
  428.  
  429. void cem3394_set_voltage(int chipnum, int input, double voltage)
  430. {
  431.     sound_chip *chip = &chip_list[chipnum];
  432.     double temp;
  433.  
  434.     /* don't do anything if no change */
  435.     if (voltage == chip->values[input])
  436.         return;
  437.     chip->values[input] = voltage;
  438.  
  439.     /* update the stream first */
  440.     stream_update(chip->stream, 0);
  441.  
  442.     /* switch off the input */
  443.     switch (input)
  444.     {
  445.         /* frequency varies from -4.0 to +4.0, at 0.75V/octave */
  446.         case CEM3394_VCO_FREQUENCY:
  447.             temp = chip->vco_zero_freq * pow(2.0, -voltage * (1.0 / 0.75));
  448.             chip->step = (UINT32)(temp * inv_sample_rate * FRACTION_ONE_D);
  449.             break;
  450.  
  451.         /* wave select determines triangle/sawtooth enable */
  452.         case CEM3394_WAVE_SELECT:
  453.             chip->wave_select &= ~(WAVE_TRIANGLE | WAVE_SAWTOOTH);
  454.             if (voltage >= -0.5 && voltage <= -0.2)
  455.                 chip->wave_select |= WAVE_TRIANGLE;
  456.             else if (voltage >=  0.9 && voltage <=  1.5)
  457.                 chip->wave_select |= WAVE_TRIANGLE | WAVE_SAWTOOTH;
  458.             else if (voltage >=  2.3 && voltage <=  3.9)
  459.                 chip->wave_select |= WAVE_SAWTOOTH;
  460.             break;
  461.  
  462.         /* pulse width determines duty cycle; 0.0 means 0%, 2.0 means 100% */
  463.         case CEM3394_PULSE_WIDTH:
  464.             if (voltage < 0.0)
  465.             {
  466.                 chip->pulse_width = 0;
  467.                 chip->wave_select &= ~WAVE_PULSE;
  468.             }
  469.             else
  470.             {
  471.                 temp = voltage * 0.5;
  472.                 if (LIMIT_WIDTH)
  473.                     temp = MINIMUM_WIDTH + (MAXIMUM_WIDTH - MINIMUM_WIDTH) * temp;
  474.                 chip->pulse_width = (UINT32)(temp * FRACTION_ONE_D);
  475.                 chip->wave_select |= WAVE_PULSE;
  476.             }
  477.             break;
  478.  
  479.         /* final gain is pretty self-explanatory; 0.0 means ~90dB, 4.0 means 0dB */
  480.         case CEM3394_FINAL_GAIN:
  481.             chip->volume = compute_db_volume(voltage);
  482.             break;
  483.  
  484.         /* mixer balance is a pan between the external input and the internal input */
  485.         /* 0.0 is equal parts of both; positive values favor external, negative favor internal */
  486.         case CEM3394_MIXER_BALANCE:
  487.             if (voltage >= 0.0)
  488.             {
  489.                 chip->mixer_internal = compute_db_volume(3.55 - voltage);
  490.                 chip->mixer_external = compute_db_volume(3.55 + 0.45 * (voltage * 0.25));
  491.             }
  492.             else
  493.             {
  494.                 chip->mixer_internal = compute_db_volume(3.55 - 0.45 * (voltage * 0.25));
  495.                 chip->mixer_external = compute_db_volume(3.55 + voltage);
  496.             }
  497.             break;
  498.  
  499.         /* filter frequency varies from -4.0 to +4.0, at 0.375V/octave */
  500.         case CEM3394_FILTER_FREQENCY:
  501.             temp = chip->filter_zero_freq * pow(2.0, -voltage * (1.0 / 0.375));
  502.             chip->filter_step = (UINT32)(temp * inv_sample_rate * FRACTION_ONE_D);
  503.             break;
  504.  
  505.         /* modulation depth is 0.01 at 0V and 2.0 at 3.5V; how it grows from one to the other */
  506.         /* is still unclear at this point */
  507.         case CEM3394_MODULATION_AMOUNT:
  508.             if (voltage < 0.0)
  509.                 chip->modulation_depth = (UINT32)(0.01 * FRACTION_ONE_D);
  510.             else if (voltage > 3.5)
  511.                 chip->modulation_depth = (UINT32)(2.00 * FRACTION_ONE_D);
  512.             else
  513.                 chip->modulation_depth = (UINT32)(((voltage * (1.0 / 3.5)) * 1.99 + 0.01) * FRACTION_ONE_D);
  514.             break;
  515.  
  516.         /* this is not yet implemented */
  517.         case CEM3394_FILTER_RESONANCE:
  518.             break;
  519.     }
  520. }
  521.  
  522.  
  523. double cem3394_get_parameter(int chipnum, int input)
  524. {
  525.     sound_chip *chip = &chip_list[chipnum];
  526.     double voltage = chip->values[input];
  527.  
  528.     switch (input)
  529.     {
  530.         case CEM3394_VCO_FREQUENCY:
  531.             return chip->vco_zero_freq * pow(2.0, -voltage * (1.0 / 0.75));
  532.  
  533.         case CEM3394_WAVE_SELECT:
  534.             return voltage;
  535.  
  536.         case CEM3394_PULSE_WIDTH:
  537.             if (voltage <= 0.0)
  538.                 return 0.0;
  539.             else if (voltage >= 2.0)
  540.                 return 1.0;
  541.             else
  542.                 return voltage * 0.5;
  543.  
  544.         case CEM3394_FINAL_GAIN:
  545.             return compute_db(voltage);
  546.  
  547.         case CEM3394_MIXER_BALANCE:
  548.             return voltage * 0.25;
  549.  
  550.         case CEM3394_MODULATION_AMOUNT:
  551.             if (voltage < 0.0)
  552.                 return 0.01;
  553.             else if (voltage > 3.5)
  554.                 return 2.0;
  555.             else
  556.                 return (voltage * (1.0 / 3.5)) * 1.99 + 0.01;
  557.  
  558.         case CEM3394_FILTER_RESONANCE:
  559.             if (voltage < 0.0)
  560.                 return 0.0;
  561.             else if (voltage > 2.5)
  562.                 return 1.0;
  563.             else
  564.                 return voltage * (1.0 / 2.5);
  565.  
  566.         case CEM3394_FILTER_FREQENCY:
  567.             return chip->filter_zero_freq * pow(2.0, -voltage * (1.0 / 0.375));
  568.     }
  569.     return 0.0;
  570. }
  571.